function supportDomTest() {
    var supportsDOM2Core = document.implementation.hasFeature("Core", "2.0");
    var supportsDOM3Core = document.implementation.hasFeature("Core", "3.0");
    var supportsDOM2HTML = document.implementation.hasFeature("HTML", "2.0");
    var supportsDOM2Views = document.implementation.hasFeature("Views", "2.0");
    var supportsDOM2XML = document.implementation.hasFeature("XML", "2.0");

    var supportsDOM2CSS = document.implementation.hasFeature("CSS", "2.0");
    var supportsDOM2CSS2 = document.implementation.hasFeature("CSS2", "2.0");
    console.log("supportsDOM2Core :" + supportsDOM2Core);
    console.log("supportsDOM3Core :" + supportsDOM3Core);
    console.log("supportsDOM2HTML :" + supportsDOM2HTML);
    console.log("supportsDOM2Views:" + supportsDOM2Views);
    console.log("supportsDOM2XML  :" + supportsDOM2XML);

    console.log("supportsDOM2CSS  :" + supportsDOM2CSS);
    console.log("supportsDOM2CSS2 :" + supportsDOM2CSS2);
}

function getStyleSheet(element) {
    return element.sheet || element.styleSheet;
}

//创建规则
function insertRule(sheet, selectorText, cssText, position) {
    if (sheet.insertRule) {
        sheet.insertRule(selectorText + "{" + cssText + "}", position);
    } else if (sheet.addRule) {
        sheet.addRule(selectorText, cssText, position);
    }
}

//删除规则
function deleteRule(sheet, index) {
    if (sheet.deleteRule) {
        sheet.deleteRule(index);
    } else if (sheet.removeRule) {
        sheet.removeRule(index);
    }
}

//获取偏移量
function getElementLeft(element) {
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;
    while (current !== null) {
        actualLeft += current.offsetLeft;
        current = current.offsetParent;
    }
    return actualLeft;
}

function getElementTop(element) {
    var actualTop = element.offsetTop;
    var current = element.offsetParent;
    while (current !== null) {
        actualTop += current.offsetTop;
        current = current.offsetParent;
    }
    return actualTop;
}

function getViewport() {
    if (document.compatMode === "BackCompat") {
        return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
        };
    } else {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
        };
    }
}

function scrollToTopTest() {
    var docHeight = Math.max(document.documentElement.scrollHeight,
        document.documentElement.clientHeight);
    var docWidth = Math.max(document.documentElement.scrollWidth,
        document.documentElement.clientWidth);
    console.log("docHeight:" + docHeight);
    console.log("docWidth:" + docWidth);
    var div = document.getElementById("scrollDiv");
    scrollToTop(div);
    var rect1 = getBoundingClientRect(div);
    console.log(rect1);
    var rect2 = getBoundingClientRect2(div);
    console.log(rect2);
}

function scrollToTop(element) {
    console.log(element.scrollTop);
    if (element.scrollTop !== 0) {
        element.scrollTop = 0;
    }
}

function getBoundingClientRect(element) {
    if (typeof arguments.callee.offset !== "number") {
        var scrollTop = document.documentElement.scrollTop;
        var temp = document.createElement("div");
        temp.style.cssText = "position:absolute;left:0;top:0;";
        document.body.appendChild(temp);
        arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
        document.body.removeChild(temp);
        temp = null;
    }
    var rect = element.getBoundingClientRect();
    var offset = arguments.callee.offset;
    return {
        left: rect.left + offset,
        right: rect.right + offset,
        top: rect.top + offset,
        bottom: rect.bottom + offset
    };
}

//兼容浏览器优化
function getBoundingClientRect2(element) {
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;
    if (element.getBoundingClientRect) {
        if (typeof arguments.callee.offset !== "number") {
            var temp = document.createElement("div");
            temp.style.cssText = "position:absolute;left:0;top:0;";
            document.body.appendChild(temp);
            arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
            document.body.removeChild(temp);
            temp = null;
        }
        var rect = element.getBoundingClientRect();
        var offset = arguments.callee.offset;
        return {
            left: rect.left + offset,
            right: rect.right + offset,
            top: rect.top + offset,
            bottom: rect.bottom + offset
        };
    } else {
        var actualLeft = getElementLeft(element);
        var actualTop = getElementTop(element);
        return {
            left: actualLeft - scrollLeft,
            right: actualLeft + element.offsetWidth - scrollLeft,
            top: actualTop - scrollTop,
            bottom: actualTop + element.offsetHeight - scrollTop
        }
    }
}

//使用下列代码可以检测浏览器对DOM2 级遍历能力的支持情况。
function supportTest() {
    var supportsTraversals = document.implementation.hasFeature("Traversal", "2.0");
    var supportsNodeIterator = (typeof document.createNodeIterator === "function");
    var supportsTreeWalker = (typeof document.createTreeWalker === "function");
}

function iteratorTest() {
//  root：想要作为搜索起点的树中的节点。
//  whatToShow：表示要访问哪些节点的数字代码。
//  filter：是一个NodeFilter 对象，或者一个表示应该接受还是拒绝某种特定节点的函数。
//  entityReferenceExpansion：布尔值，表示是否要扩展实体引用。这个参数在HTML 页面
//     中没有用，因为其中的实体引用不能扩展。

//  NodeFilter.SHOW_ALL：显示所有类型的节点。
//  NodeFilter.SHOW_ELEMENT：显示元素节点。
//  NodeFilter.SHOW_ATTRIBUTE：显示特性节点。由于DOM结构原因，实际上不能使用这个值。
//  NodeFilter.SHOW_TEXT：显示文本节点。
//  NodeFilter.SHOW_CDATA_SECTION：显示CDATA 节点。对HTML 页面没有用。
//  NodeFilter.SHOW_ENTITY_REFERENCE：显示实体引用节点。对HTML 页面没有用。
//  NodeFilter.SHOW_ENTITYE：显示实体节点。对HTML 页面没有用。
//  NodeFilter.SHOW_PROCESSING_INSTRUCTION：显示处理指令节点。对HTML 页面没有用。
//  NodeFilter.SHOW_COMMENT：显示注释节点。
//  NodeFilter.SHOW_DOCUMENT：显示文档节点。
//  NodeFilter.SHOW_DOCUMENT_TYPE：显示文档类型节点。
//  NodeFilter.SHOW_DOCUMENT_FRAGMENT：显示文档片段节点。对HTML 页面没有用。
//  NodeFilter.SHOW_NOTATION：显示符号节点。对HTML 页面没有用。

    var div = document.getElementById("div1");
    var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT,
        null, false);
    var node = iterator.nextNode();
    while (node !== null) {
        console.log(node.tagName); //输出标签名
        node = iterator.nextNode();
    }
    console.log("filter-------------------------------");
    var filter = function (node) {
        return node.tagName.toLowerCase() === "li" ?
            NodeFilter.FILTER_ACCEPT :
            NodeFilter.FILTER_SKIP;
    };
    var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false);
    var node = iterator.nextNode();
    while (node !== null) {
        console.log(node.tagName); //输出标签名
        node = iterator.nextNode();
    }
}

//IE不支持
function createTreeWalkerTest() {
    var div = document.getElementById("div1");
    var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false);
    walker.firstChild(); //转到<p>
    walker.nextSibling(); //转到<ul>
    var node = walker.firstChild(); //转到第一个<li>
    while (node !== null) {
        alert(node.tagName);
        node = walker.nextSibling();
    }
}

//DOM中的范围
function rangeSupport() {
    var supportsRange = document.implementation.hasFeature("Range", "2.0");
    var alsoSupportsRange = (typeof document.createRange === "function");
//  startContainer：包含范围起点的节点（即选区中第一个节点的父节点）。
//  startOffset：范围在startContainer 中起点的偏移量。如果startContainer 是文本节
//     点、注释节点或CDATA 节点，那么startOffset 就是范围起点之前跳过的字符数量。否则，
// startOffset 就是范围中第一个子节点的索引。
//  endContainer：包含范围终点的节点（即选区中最后一个节点的父节点）。
//  endOffset：范围在endContainer 中终点的偏移量（与startOffset 遵循相同的取值规则）。
//  commonAncestorContainer：startContainer 和endContainer 共同的祖先节点在文档树
//     中位置最深的那个。
}

function rangeTest() {
    var range1 = document.createRange();
    var range2 = document.createRange();
    var p1 = document.getElementById("p1");
    var showDiv = document.getElementById("showDiv");
    console.log(p1);
    range1.selectNode(p1);
    range2.selectNodeContents(p1);
    console.log(range1.cloneContents());//<p id="p1"><b>Hello</b> world!</p>
    console.log(range2.cloneContents());//<b>Hello</b> world!
    showDiv.innerHTML += "range1:";
    showDiv.appendChild(range1.cloneContents());
    showDiv.innerHTML += "range2:";
    showDiv.appendChild(range2.cloneContents());
    //---------------------------------------------
    var range3 = document.createRange();
    var range4 = document.createRange();
    var p1Index = -1;
    var i, len;
    for (i = 0, len = p1.parentNode.childNodes.length; i < len; i++) {
        if (p1.parentNode.childNodes[i] === p1) {
            p1Index = i;
            break;
        }
    }
    range3.setStart(p1.parentNode, p1Index);
    range3.setEnd(p1.parentNode, p1Index + 1);
    range4.setStart(p1, 0);
    range4.setEnd(p1, p1.childNodes.length);
    console.log(range3.cloneContents());
    console.log(range4.cloneContents());
    showDiv.innerHTML += "<br>range3:";
    showDiv.appendChild(range3.cloneContents());
    showDiv.innerHTML += "range4:";
    showDiv.appendChild(range4.cloneContents());
    //---------------------------------------------
    var helloNode = p1.firstChild.firstChild;
    var worldNode = p1.lastChild;
    var range5 = document.createRange();
    range5.setStart(helloNode, 2);
    range5.setEnd(worldNode, 3);
    console.log(range5.cloneContents());

    showDiv.innerHTML += "<br>range5:";
    showDiv.appendChild(range5.cloneContents());
    showDiv.innerHTML += "<br>";
}

function insertNodeTest() {
    var p1 = document.getElementById("p1");
    var helloNode = p1.firstChild.firstChild;
    var worldNode = p1.lastChild;
    var range = document.createRange();
    range.setStart(helloNode, 2);
    range.setEnd(worldNode, 3);
    console.log(range.cloneContents());

    var span = document.createElement("span");
    span.style.color = "red";
    span.appendChild(document.createTextNode("Inserted text"));
    range.insertNode(span);
    console.log(range.cloneContents());
}

function surroundContentsTest() {
    var p1 = document.getElementById("p1");
    var helloNode = p1.firstChild.firstChild;
    var worldNode = p1.lastChild;
    var range = document.createRange();
    range.selectNode(helloNode);
    console.log(range.cloneContents());

    var span = document.createElement("span");
    span.style.backgroundColor = "yellow";
    range.surroundContents(span);
    console.log(range.cloneContents());
}

function compareRange() {
//  Range.START_TO_START(0)：比较第一个范围和第二个范围的起点；
//  Range.START_TO_END(1)：比较第一个范围的起点和第二个范围的终点；
//  Range.END_TO_END(2)：比较第一个范围和第二个范围的终点；
//  Range.END_TO_START(3)：比较第一个范围的终点和第一个范围的起点。
// compareBoundaryPoints()方法可能的返回值如下：如果第一个范围中的点位于第二个范围中的
//     点之前，返回-1；如果两个点相等，返回0；如果第一个范围中的点位于第二个范围中的点之后，返回
//     1。
    var range1 = document.createRange();
    var range2 = document.createRange();
    var p1 = document.getElementById("p1");
    range1.selectNodeContents(p1);
    range2.selectNodeContents(p1);
    range2.setEndBefore(p1.lastChild);
    alert(range1.compareBoundaryPoints(Range.START_TO_START, range2)); //0
    alert(range1.compareBoundaryPoints(Range.END_TO_END, range2)); //1
}